package com.sgx.learning.luban.homework.attributes.ext.stackmapframe;

import com.sgx.learning.luban.homework.attributes.ext.stackmapframe.checkvariable.*;
import com.sgx.learning.luban.homework.basictype.U1;
import com.sgx.learning.luban.homework.constantpool.ConstantPoolInfo;
import lombok.Data;

import java.io.IOException;
import java.io.InputStream;

@Data
public abstract class StackMapFrame {

    private int frameType;

    public abstract void read(InputStream is, ConstantPoolInfo[] constantPoolInfos) throws IOException;

    public static StackMapFrame selectStackMapFrame(InputStream inputStream,ConstantPoolInfo[] constantPoolInfos) throws IOException {
        byte fT = U1.read(inputStream).getValue();
        int st = fT & 0xFF;
        StackMapFrame res = null;
        if(st < 64) {
            res = new SameFrame();
        } else if(st < 128) {
            res = new SameLocals1StackItemFrame();
        } else if(st <= 246) {

        } else if( 247 == st) {
            res = new SameLocals1StackItemFrameExtended();
        } else if( 250 >= st) {
            res = new ChopFrame();
        } else if(251 == st){
            res = new SameFrameExtended();
        } else if(254 >= st) {
            res = new AppendFrame();
        } else if(255 == st) {
            res = new FullFrame();
        }
        if(res != null) {
            res.setFrameType(st);
            res.read(inputStream,constantPoolInfos);
        }
        return res;
    }

    protected VerificationTypeInfo getTagFromInputStream(InputStream is) throws IOException {
        byte typeTag = U1.read(is).getValue();
        VerificationTypeInfo verificationTypeInfo = null;
        switch (typeTag) {
            case VerificationTypeInfo.TOP_VARIABLE_INFO:{
                verificationTypeInfo = new TopVariableInfo();
            }break;
            case VerificationTypeInfo.INTEGER_VARIABLE_INFO:{
                verificationTypeInfo = new IntegerVariableInfo();
            }break;
            case VerificationTypeInfo.FLOAT_VARIABLE_INFO:{
                verificationTypeInfo = new FloatVariableInfo();
            }break;
            case VerificationTypeInfo.LONG_VARIABLE_INFO:{
                verificationTypeInfo = new LongVariableInfo();
            }break;
            case VerificationTypeInfo.DOUBLE_VARIABLE_INFO:{
                verificationTypeInfo = new DoubleVariableInfo();
            }break;
            case VerificationTypeInfo.NULL_VARIABLE_INFO:{
                verificationTypeInfo = new NullVariableInfo();
            }break;
            case VerificationTypeInfo.UNINITIALIZED_THIS_VARIABLE_INFO:{
                verificationTypeInfo = new UninitializedThisVariableInfo();
            }break;
            case VerificationTypeInfo.OBJECT_VARIABLE_INFO:{
                verificationTypeInfo = new ObjectVariableInfo();
            }break;
            case VerificationTypeInfo.UNINITIALIZED_VARIABLE_INFO:{
                verificationTypeInfo = new UninitializedVariableInfo();
            }break;
            default:break;
        }
        if(verificationTypeInfo != null) {
            verificationTypeInfo.read(is);
        }
        return verificationTypeInfo;
    }
}
